(2024/04/06更新) 因應React在18後更新了許多不同的語法,更新後的教學之後將陸續放在 新的blog 中,歡迎讀者到該處閱讀,我依然會回覆這邊的提問
在過去的29天內,除了直接綁在JSX元素上外,我們從來都沒有提過要如何在React處理CSS code。其實只要設定好打包工具,我們就能直接在任何元件檔使用import引入css檔。例如如果你是使用create-react-app建立專案的朋友,就能這樣寫:
import ".css檔路徑";
然而這樣做有個問題。
一般在做SPA的時候,通常是把所有css檔打包成一個或多個檔案,並在第一次載入網頁時就全部引入。但這會讓開發者原本想要隸屬於個別元件的css程式碼同時生效,導致本來應該分開的css程式碼互相影響。 如果想要最簡易的解決這個問題,除了把style寫在JSX的props上外,就要引用第三方套件。
除非你能保證,你自己、你的同事、你未來的接班人、你過去的古人(?) 都沒有使用同樣的class、id 或是其他哩哩摳摳的選取器......
現在,我們就來介紹一款熱門的React style處理套件 - Styled-Components
請打開terminal,輸入:
npm install --save styled-components
Styled-Component可以讓我們撰寫css code後,產生「專屬這組css」的React元件。他的語法很特別:
import styled from 'styled-components';
const 元件 = styled.你想使用的DOM元素`css程式碼`
//在JSX使用時
<元件></元件>
css程式碼要在.js檔以字串的方式寫在最後面。舉例來說,本來我們的MenuItem長這樣:
import React, { memo } from 'react';
const menuItemStyle = {
marginBottom: "7px",
paddingLeft: "26px",
listStyle: "none"
};
function MenuItem(props){
return <li style={menuItemStyle}>{props.text}</li>;
}
export default memo(MenuItem);
切換成Styled-Components後就會變這樣:
import React, { memo } from 'react';
import styled from 'styled-components';
const MenuStyleItem = styled.li`
margin-bottom: 7px;
padding-left: 26px;
list-style: none;
`;
function MenuItem(props){
return <MenuStyleItem>{props.text}</MenuStyleItem>;
}
export default memo(MenuItem);
實際觀看執行結果,你會發現顯示的雖然是一般的<li>
,但它上面多了一組特別的class,而且我們撰寫的css程式碼自動以這個class為選取器運作:
因為相同的Styled-Components元件會產生同樣且不與其他元件重複的class,所以我們就能避免在不同地方使用到相同css選取器而互相影響。
另外,一般會習慣把定義Styled-Components的地方拉出來和本來的元件分開。就跟以前會把css跟html檔分開的感覺很像。只是現在你又能更方便的製造相同style的元素:
import styled from 'styled-components';
const MenuStyleItem = styled.li`
margin-bottom: 7px;
padding-left: 26px;
list-style: none;
`;
export { MenuStyleItem };
import React, { memo } from 'react';
import { MenuStyleItem } from './MenuItemStyle';
function MenuItem(props){
return <MenuStyleItem>{props.text}</MenuStyleItem>;
}
export default memo(MenuItem);
你可以在Styled-Components上直接綁定本來原生DOM元素就會運作的props,例如onClick
,該props會自動被給予DOM元素,不需要做任何而外的事情。
另外,我們也能透過ES6的字串模板,讓css根據props的值而變動。像是下面我們給了MenuStyleItem一個color={"blue"}
:
import React, { memo } from 'react';
import { MenuStyleItem } from './MenuItemStyle';
function MenuItem(props){
return <MenuStyleItem color={"blue"}>{props.text}</MenuStyleItem>;
}
export default memo(MenuItem);
我們就能把props.color
設為color
的值(如果沒有給props.color
則把color設定為"black"
)。
import styled from 'styled-components';
const MenuStyleItem = styled.li`
margin-bottom: 7px;
padding-left: 26px;
list-style: none;
color: ${props => props.color ? props.color : "black"};
`;
export { MenuStyleItem };
你可以透過Styled元件.defaultProps
來設定給參數預設值。藉此達到製作「主題」的效果。當使用元件的人沒有給對應的style的props時,Styled元件就會以預設的參數造型顯示:
import styled from 'styled-components';
const MenuStyleItem = styled.li`
margin-bottom: 7px;
padding-left: 26px;
list-style: none;
color: ${props => props.theme.color};
`;
MenuStyleItem.defaultProps = {
theme: {
color: "mediumseagreen"
}
}
export {MenuStyleItem};
import React, { memo } from 'react';
import { MenuStyleItem } from './MenuItemStyle';
function MenuItem(props){
return <MenuStyleItem>{props.text}</MenuStyleItem>;
}
export default memo(MenuItem);
另外你也可以透過搭配useContext或是Redux達到製造相同主題的效果,這裡就不示範了。
最後,比較乾淨的分檔方式應該是為單一元件創立一個資料夾,在裡面放置專屬於它的元件程式和style程式。但這個就是不同人/團隊的習慣問題了。
import React, { memo } from 'react';
import { MenuStyleItem } from './style';
function MenuItem(props){
return <MenuStyleItem onClick={()=>{console.log(props.handleClick)}}>{props.text}</MenuStyleItem>;
}
export default memo(MenuItem);
import styled from 'styled-components';
const MenuStyleItem = styled.li`
margin-bottom: 7px;
padding-left: 26px;
list-style: none;
color: ${props => props.theme.color};
`;
MenuStyleItem.defaultProps = {
theme: {
color: "mediumseagreen"
}
}
export {MenuStyleIStyleItem};
另外,StyleComponent中也能撰寫像是偽元素的語法,更多進階使用可以參考官方文件
在這個系列中,除了這兩個hook之外
我們已經把所有其他官方提供的React hook、現今業界React專案開發一定會用到的語法、套件以及他們需要用到的對應情境都講解了一遍。上面這兩個有需要的時候再去查就好。
有關React SSR的文章我應該會後續幾個月內再繼續發,到時候也是會發在這個系列。
最後,我希望看這系列文的讀者不是只為了工作才逼自己跟隨React語法寫程式,而是能夠理解框架是長期演變而來的。所謂的框架,只是把過去開發者發現中大型專案幾乎一定會用到的Design Pattern、架構都幫你封裝好。我們應該思考的是如何讓「元件化的架構」搭配框架提供的功能而變得更乾淨、更好用、更能彈性的封裝,而不是單純寫出一個能用的React Component。
這30天的內容如果都能理解並熟悉,我相信在2020年你絕對能夠用React找到一份工作。
因為2020年只剩2個月了,讀者練完這系列、投完履歷,2個月應該也過了......
今年我沒有先準備。而且在參賽的期間,我同時要實習、準備推甄、準備另一個比賽、準備通識報告......可以完賽我真的覺得不可思議。
在撰寫技術教學文的時候,我會希望在介紹一個新單元時,應該要從「為什麼需要這個工具」開始,慢慢從「為什麼架構要這樣設計」,再繼續去提他的語法跟用法。雖然自己不是讀者很難判斷是不是這樣,但希望這次我有做到這個目標。
如果這中間有哪篇不清楚、有寫錯的地方,或是你看完這系列之後有什麼想跟我交流的,都歡迎留言在底下跟我說。